package zyf.jmidifile.test;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;

import zyf.jmidifile.JMidiEvent;
import zyf.jmidifile.JMidiFile;
import zyf.jmidifile.JMidiPlayer;
import zyf.jmidifile.JMidiTrack;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private TextView mainLabel;
    private TextView durationLabel;
    private TextView currTimeLabel;
    private SeekBar progressBar;
    private JMidiFile midiFile;
    private JMidiPlayer midiPlayer;
    private TrackAdapter adapter;

    static private final String MIDI_FILE_NAME = "fly-me-to-the-moon.mid";

    static private final String TAG = "jmiditest";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainLabel = (TextView) findViewById(R.id.tv_main);
        durationLabel = (TextView) findViewById(R.id.tv_duration);
        currTimeLabel = (TextView) findViewById(R.id.tv_curr_time);
        progressBar = (SeekBar) findViewById(R.id.sb_progress);
        initTrackView();

        try {
            loadMidiFile(getAssets().open(MIDI_FILE_NAME));
        } catch (IOException e) {
            e.printStackTrace();
        }
        initPlayBtn();
        initProgressBar();
        initTestWriteBtn();
    }

    private void loadMidiFile(InputStream in) {
        mainLabel.setText("开始加载 midi 文件");
        long duration = 0;
        try {
            midiFile = new JMidiFile(in);
            duration = midiFile.getDuration(-1);
        } catch (IOException e) {
            e.printStackTrace();
            mainLabel.setText("加载 midi 文件失败");
            return;
        }
        mainLabel.setText("加载 midi 文件成功");

        initPlayer();

        setCurrTime(0);
        progressBar.setMax((int) duration);
        durationLabel.setText(toMinSecStr(duration));
        adapter.clear();
    }

    private void initPlayer() {
        if (midiFile == null) return;

        // build player
        midiPlayer = new JMidiPlayer(midiFile, false);

        midiPlayer.addEventListener(new JMidiPlayer.EventListener() {
            @Override
            public void onStateChange(JMidiPlayer player, int oldState, int newState) {
                if (newState != JMidiPlayer.STATE_PLAYING) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Button btn = (Button) findViewById(R.id.btn_play);
                            btn.setText("play");
                        }
                    });
                }
            }

            @Override
            public void onEvents(JMidiPlayer player, int tid, List<JMidiEvent> events, boolean isResumedNotes) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        for (JMidiEvent e : events) {
                            adapter.add(e);
                        }
                    }
                });
            }

            @Override
            public void onUpdate(JMidiPlayer player, long deltaMs) {
                final long ms = player.getCurrentTime();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (player == midiPlayer) {
                            setCurrTime(ms);
                        }
                    }
                });
            }
        });
    }

    private void setCurrTime(long ms) {
        currTimeLabel.setText(toMinSecStr(ms));
        progressBar.setProgress((int) ms);
    }

    private void initTrackView() {
        adapter = new TrackAdapter();
        RecyclerView view = (RecyclerView) findViewById(R.id.rv_track);
        view.setLayoutManager(new LinearLayoutManager(this));
        view.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); // 添加分割线
        view.setAdapter(adapter);
    }

    private void initPlayBtn() {
        Button btn = (Button) findViewById(R.id.btn_play);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                togglePlay();
            }
        });
    }

    private void initProgressBar() {
        progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser) {
                    currTimeLabel.setText(toMinSecStr(progress));
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                if (midiPlayer != null) {
                    midiPlayer.pause();
                }
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                if (midiPlayer != null) {
                    midiPlayer.seek(seekBar.getProgress());
                }
            }
        });
    }

    private void togglePlay() {
        if (midiPlayer == null) return;

        Button btn = (Button) findViewById(R.id.btn_play);
        if (midiPlayer.getState() == JMidiPlayer.STATE_PLAYING) {
            midiPlayer.pause();
            btn.setText("play");
        } else {
            midiPlayer.play();
            btn.setText("pause");
        }
    }

    private void initTestWriteBtn() {
        Button btn = (Button) findViewById(R.id.btn_save_file);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testWrite();
            }
        });
    }

    private void testWrite() {
        mainLabel.setText("开始测试写入文件");
        // 停止播放器播放
        midiPlayer.stop();
        midiPlayer.clearEventListeners();
        midiPlayer = null;
        // 写入文件测试
        JMidiFile file = new JMidiFile(240);
        // 写 meta 信息
        JMidiTrack metaTrack = new JMidiTrack();
        JMidiEvent e = new JMidiEvent(0L);
        e.setTimeSign(6, 8);
        metaTrack.add(e);
        e = new JMidiEvent(0L);
        e.setBPM(90);
        metaTrack.add(e);
        file.addTrack(metaTrack);

        // 写旋律轨 1
        JMidiTrack track = new JMidiTrack();
        e = new JMidiEvent(0L);
        e.setTimbre(0, 0);
        track.add(e);
        for (int i = 0; i < 12; ++i) {
            e = new JMidiEvent(500L * i);
            e.setNoteOn(0, 60, ((i % 2) == 0) ? 80 : 0);
            track.add(e);
        }
        file.addTrack(track);

        // 写打击轨 2
        track = new JMidiTrack();
        e = new JMidiEvent(0L);
        e.setTimbre(9, 0);
        for (int i = 0; i < 6; ++i) {
            e = new JMidiEvent(1000L * i);
            e.setNoteOn(9, 38, ((i % 2) == 0) ? 64 : 0);
            track.add(e);
        }
        file.addTrack(track);

        String savePath = getFilesDir().getAbsolutePath() + "/test.mid";
        try {
            file.save(savePath);
        } catch (IOException exception) {
            exception.printStackTrace();
            mainLabel.setText("写入测试文件失败");
            return;
        }

        mainLabel.setText("测试写入成功");
        // 重新载入文件
        try {
            loadMidiFile(new FileInputStream(savePath));
        } catch (FileNotFoundException exception) {
            exception.printStackTrace();
            mainLabel.setText("加载写入的文件失败");
        }
    }

    public static String toMinSecStr(long ms) {
        if (ms < 0) {
            ms = 0;
        }
        long secs = (long) (ms / 1000.0 + 0.5);
        long min = secs / 60;
        long sec = secs - min * 60;

        return String.format("%02d:%02d", min, sec);
    }

    protected void onPause() {
        super.onPause();
        if (midiPlayer.getState() == JMidiPlayer.STATE_PLAYING) {
            midiPlayer.pause();
        }
    }
}
